﻿using System;
using System.ComponentModel;
using System.Net;
using System.Net.Mail;

namespace Kaio.Net.Email
{
    public class Smtp : IEmail
    {

        private readonly SmtpClient _smtpClient;
        private readonly NetworkCredential _credentials = new NetworkCredential();
        public string Server { get; set; }
        public int Port { get; set; }

        public bool EnableSsl { get; set; }

        /// <summary>
        /// Gets or sets a value which is used to 
        /// configure if emails are going to be sent asyncrhonously or not.
        /// </summary>
        public bool AsyncSend { get; set; }

        /// <summary>
        /// Gets or sets a value that specifies 
        /// the amount of time after which a synchronous Send call times out.
        /// </summary>
        public int Timeout
        {
            get { return _smtpClient.Timeout; }
            set { _smtpClient.Timeout = value; }
        }

        /// <summary>
        /// Gets or sets the name of the user.
        /// </summary>
        /// <value>The name of the user.</value>
        public String UserName
        {
            get { return _credentials.UserName; }
            set { _credentials.UserName = value; }
        }

        /// <summary>
        /// Gets or sets the password.
        /// </summary>
        /// <value>The password.</value>
        public String Password
        {
            get { return _credentials.Password; }
            set { _credentials.Password = value; }
        }

        public Smtp(string host)
        {
            _smtpClient = new SmtpClient(host);
        }


        public Smtp(string host, int port)
        {
            _smtpClient = new SmtpClient(host, port);
        }

        public MailPriority Priority { get; set; }



        /// <summary>
        /// Sends a message. 
        /// </summary>
        /// <exception cref="ArgumentNullException">If any of the parameters is null</exception>
        /// <param name="from">From field</param>
        /// <param name="to">To field</param>
        /// <param name="subject">e-mail's subject</param>
        /// <param name="messageText">message's body</param>
        public void Send(string from, string to, string subject, string messageText)
        {
            if (from == null) throw new ArgumentNullException("from");
            if (to == null) throw new ArgumentNullException("to");
            if (subject == null) throw new ArgumentNullException("subject");
            if (messageText == null) throw new ArgumentNullException("messageText");

            Send(new MailMessage(from, to.Replace(";",","), subject, messageText));

        }

        public void Send(MailMessage message)
        {
            if (message == null) throw new ArgumentNullException("message");

            if (HasCredentials)
            {
                _smtpClient.Credentials = _credentials;
            }

            _smtpClient.EnableSsl = EnableSsl;

            if (AsyncSend)
            {
                // The MailMessage must be diposed after sending the email.
                // The code creates a delegate for deleting the mail and adds
                // it to the smtpClient.
                // After the mail is sent, the message is disposed and the
                // eventHandler removed from the smtpClient.
                MailMessage msg =message;
                Guid msgGuid = new Guid();
                SendCompletedEventHandler sceh = null;
                sceh = delegate(object sender, AsyncCompletedEventArgs e)
                {
                    if (msgGuid == (Guid)e.UserState)
                        msg.Dispose();
                    // The handler itself, cannot be null, test omitted
                    _smtpClient.SendCompleted -= sceh;
                };
                _smtpClient.SendCompleted += sceh;
                _smtpClient.SendAsync(msg, msgGuid);
            }
            else
            {
                using (MailMessage msg = message)
                {
                    _smtpClient.Send(msg);
                }
            }


        }

        public void Send(MailMessage[] messages)
        {
            foreach (var msg in messages)
            {
                Send(msg);
            }
        }


        protected bool HasCredentials
        {
            get { return _credentials.UserName != null && _credentials.Password != null; }
        }
    }
}
